#include "sh_mem.h"
#include "string.h"
#include "os_mem.h"
#include "sw_interrupt.h"


err_t create_shared_memory(const uint8_t *name, shm_open_mode_t open_mode, 
     uint16_t size, void **handle, void **address, bool *created)
{
    dev_handle_t *dev_handle;
    err_t err_code;

    if (!name || !size || strlen(name) == 0) {
        //printf("Invalid name/size/strlen(name). %s 0x%x\n", name, size);
        return ERR_INVALID;
    }

    if (open_mode != SHM_CREATE_ALWAYS && open_mode != SHM_CREATE_IF_NOT_FOUND) {
        //printf("Invalid open mode\n");
        return ERR_INVALID;
    }

    dev_handle = (dev_handle_t *)calloc(1, sizeof(dev_handle_t));
    if (!dev_handle) { return ERR_NO_MEM; }

    dev_handle->dev_info.name = calloc(1, strlen(name)+1);
    if (!dev_handle->dev_info.name) {
        free(dev_handle);
	return ERR_NO_MEM;
    }

    strcpy((uint8_t *)dev_handle->dev_info.name, name);
    dev_handle->dev_info.type = DEVICE_TYPE_SHMEM;
    dev_handle->dev_info.size  = size;
    dev_handle->open_mode = open_mode;
    dev_handle->access_info.permissions = DEVICE_MODE_WRITE;

    raise_sw_interrupt(SW_INT_DEVICE_OPEN, (uint32_t)dev_handle);
  
    err_code = dev_handle->err_code;
    if (dev_handle->err_code == ERR_SUCCESS) {
        *handle = (void *)dev_handle;
	*address = (void *)dev_handle->dev_info.address;
	*created = dev_handle->device_created;
    } else {
        free((void *)dev_handle->dev_info.name);
	free((void *)dev_handle);
    }

    return err_code;
}


err_t close_shared_memory(void *handle)
{
    dev_handle_t *dev_handle = (dev_handle_t *)handle;
    err_t err_code;

    if (!handle || !dev_handle->dev_info.name) { return ERR_INVALID; }

    raise_sw_interrupt(SW_INT_DEVICE_CLOSE, (uint32_t)handle);

    err_code = dev_handle->err_code;
    if (dev_handle->err_code == ERR_SUCCESS) {
        free((void *)dev_handle->dev_info.name);
	dev_handle->dev_info.name = NULL;
	free(dev_handle);
    }

    return err_code;
}


err_t open_shared_memory(const uint8_t *name, void **handle, void **address)
{
    dev_handle_t *dev_handle;
    err_t err_code;

    if (!name || strlen(name) == 0) {
        return ERR_INVALID;
    }

    dev_handle = (dev_handle_t *)calloc(1, sizeof(dev_handle_t));
    if (!dev_handle) { return ERR_NO_MEM; }

    dev_handle->dev_info.name = calloc(1, strlen(name)+1);
    if (!dev_handle->dev_info.name) {
        free(dev_handle);
	return ERR_NO_MEM;
    }

    strcpy((uint8_t *)dev_handle->dev_info.name, name);
    dev_handle->dev_info.type = DEVICE_TYPE_SHMEM;
    dev_handle->open_mode = DEVICE_MODE_OPEN_EXISTING;
    dev_handle->access_info.permissions = DEVICE_MODE_WRITE;

    raise_sw_interrupt(SW_INT_DEVICE_OPEN, (uint32_t)dev_handle);
  
    err_code = dev_handle->err_code;
    if (dev_handle->err_code == ERR_SUCCESS) {
        *handle = (void *)dev_handle;
	*address = (void *)dev_handle->dev_info.address;
    } else {
        free((void *)dev_handle->dev_info.name);
	free(dev_handle);
    }

    return err_code;
}
